import sys
import os
import pickle
from tkinter import *
from tkinter.messagebox import *

def writeFile(filename, var):
	f = open(filename, "wb")
	pickle.dump(var, f, 2)  # 默认是0，表示文本, 1表示老式的二进制协议；2表示新二进制协议
	f.close()

def readFile(filename):
	f = open(filename, "rb")
	try:
		data = pickle.load(f).decode("utf-8")
	except EOFError:
		data = ""
	finally:
		f.close()
	return data

class Main:
    def __init__(self, filename):
        if os.path.exists(filename):
            self.pwd_content_data = readFile(filename)
        else:
            self.pwd_content_data = ""
        if filename == "":
            showinfo("", "请在调用时加上文件名！")
            return
        self.filename = filename
        self.pwd_content_data_src = self.pwd_content_data
        self.can_save = True
        
        self.init_root()
    
    def init_root(self):
        self.root = Tk()
        self.root.title("pwd note helper")
        self.root.protocol("WM_DELETE_WINDOW", self.on_exit)
        self.root.resizable(height=False, width=False)
        self.window_w = int(self.root.winfo_screenwidth() * 0.75)
        self.window_h = int(self.root.winfo_screenheight() * 0.6)
        window_w = self.window_w + 40
        window_h = self.window_h + 50
        self.root.minsize(window_w, window_h)
        screenleft = (self.root.winfo_screenwidth() - window_w) // 2 + 20
        screentop = (self.root.winfo_screenheight() - window_h) // 2 + 20
        self.root.geometry(f"{window_w}x{window_h}+{screenleft}+{screentop}")
        self.pixel_width_per_char = 8  # 经过大致观察，每个字符宽度约8个像素单位
        self.pixel_height_per_char = 17.3  # 经过大致观察，每个字符高度约17.3个像素单位
        self.scroll_bar_width = 13  # 滚动条的宽度默认为13个像素单位: scrollbar_v.winfo_reqwidth(), scrollbar_h.winfo_reqheight()

        self.init_frame1()
        self.init_frame2()
        
        self.root.mainloop()
    
    def init_frame1(self):
        frame1 = Frame(self.root)
        frame1.grid(row = 1, columnspan = 1, sticky=W+E)

        self.buttonSave = Button(frame1, text="保存", command=self.save)
        self.search_entry_left_size = self.buttonSave.winfo_reqwidth()
        self.pwd_text_left_size = self.buttonSave.winfo_reqheight()
        self.buttonSave.grid(row = 0, column = 0, sticky=W, padx = 5, pady = 5)

        buttonClear = Button(frame1, text="清空搜索", command=self.clear)
        self.search_entry_left_size += buttonClear.winfo_reqwidth()
        buttonClear.grid(row = 0, column = 1, sticky=W, padx = 5, pady = 5)

        entry_change_cmd = self.root.register(self.entry_change)
        search_entry_width = (self.window_w - self.search_entry_left_size) // self.pixel_width_per_char
        self.search_entry = Entry(frame1, width=search_entry_width, textvariable = "", validate='key', validatecommand = (entry_change_cmd, '%P', '%v', '%W'))
        self.search_entry.grid(row = 0, column = 2, sticky=W, padx = 5, pady = 5)
        self.search_entry.bind("<Control-Key-a>", self.select_all_entry)
        self.search_entry.bind("<Control-Key-A>", self.select_all_entry)
    
    def init_frame2(self):
        self.frame2 = Frame(self.root)
        self.frame2.grid(row = 2, columnspan = 1, sticky=W+E)

        pwd_text_width = (self.window_w - self.scroll_bar_width + 20) // self.pixel_width_per_char  # 上面的控件积累多出了20个像素单位
        pwd_text_height = (self.window_h - self.scroll_bar_width) // self.pixel_height_per_char
        self.pwd_text = Text(self.frame2, width=pwd_text_width, height=pwd_text_height, wrap="none")
        self.pwd_text.insert("end", self.pwd_content_data[:-1])
        self.pwd_text.grid(row = 0, column = 0, sticky=W, padx = 5, pady = 5)
        self.pwd_text.bind("<Control-Key-a>", self.select_all_text)
        self.pwd_text.bind("<Control-Key-A>", self.select_all_text)
        self.pwd_text.bind("<Control-Key-s>", self.save_ctrl_s)
        self.pwd_text.bind("<Control-Key-S>", self.save_ctrl_s)

        scrollbar_v = Scrollbar(self.frame2)
        scrollbar_v.grid(row = 0, column = 1, sticky="ns")
        scrollbar_v.config(command = self.pwd_text.yview)
        self.pwd_text.config(yscrollcommand = scrollbar_v.set)

        scrollbar_h = Scrollbar(self.frame2, orient=HORIZONTAL)
        scrollbar_h.grid(row = 1, column = 0, sticky="we")
        scrollbar_h.config(command = self.pwd_text.xview)
        self.pwd_text.config(xscrollcommand = scrollbar_h.set)
        self.pwd_text_left_size += scrollbar_h.winfo_reqheight()
    
    def save(self):
        self.__save()
    
    def save_ctrl_s(self, event):
        self.__save()
    
    def __save(self):
        if not self.can_save:
            return
        data = self.pwd_text.get(1.0, "end")
        self.pwd_content_data = data
        self.pwd_content_data_src = self.pwd_content_data
        writeFile(self.filename, data.encode("utf-8"))
        showinfo("", "保存成功")

    def clear(self):
        self.search_entry.delete(0, END)
        self.reset()

    def reset(self):
        self.can_save = True
        self.buttonSave.config(state=NORMAL)
        self.pwd_text.delete(1.0, "end")
        self.pwd_text.insert("end", self.pwd_content_data_src[:-1])
    
    def select_all_entry(self, event):
        self.search_entry.selection_range(0, END)
        return 'break'
    
    def select_all_text(self, event):
        self.pwd_text.tag_add('sel', '1.0', 'end')
        return 'break'
    
    def search(self, key_str):
        self.can_save = False
        self.buttonSave.config(state=DISABLED)
        keys = [i.lower() for i in key_str.split(" ") if i != ""]
        lines = [i for i in self.pwd_content_data.split("\n") if i != ""]
        s_lines = []
        for i in lines:
            flag = True
            for j in keys:
                if j not in i.lower():
                    flag = False
                    break
            if flag:
                s_lines.append(i)
        self.pwd_text.delete(1.0, "end")
        self.pwd_text.insert("end", "\n".join(s_lines))
    
    def entry_change(self, key_str, validate, widget):
        key_str = key_str.strip()
        if key_str == "":
            self.reset()
        else:
            self.search(key_str)
        return True
    
    def on_exit(self):
        if self.can_save and self.pwd_content_data != self.pwd_text.get(1.0, "end"):
            flag = askyesno("", "是否保存？")
            if flag:
                self.__save()
        self.root.destroy()

if __name__ == '__main__':
	file = "" if len(sys.argv) == 1 else sys.argv[1]
	Main(file)
